[XEN] Allow log-dirty mode to be enabled on already-shadowed domains.
authorTim Deegan <Tim.Deegan@xensource.com>
Mon, 26 Feb 2007 13:56:01 +0000 (13:56 +0000)
committerTim Deegan <Tim.Deegan@xensource.com>
Mon, 26 Feb 2007 13:56:01 +0000 (13:56 +0000)
and catch a few missing mark_dirty() calls
Signed-off-by: Tim Deegan <Tim.Deegan@xensource.com>
xen/arch/x86/hvm/hvm.c
xen/arch/x86/hvm/io.c
xen/arch/x86/mm/shadow/common.c
xen/arch/x86/mm/shadow/multi.c
xen/arch/x86/mm/shadow/private.h
xen/include/asm-x86/shadow.h

index 0d30ac7a1157c0e7fba811ff87c0e43906fc1aa5..326f3c0ed39e627232931ad36474d3923f22adef 100644 (file)
@@ -398,6 +398,8 @@ static int __hvm_copy(void *buf, paddr_t addr, int size, int dir, int virt)
             memcpy(buf, p, count); /* dir == FALSE: *from guest */
 
         unmap_domain_page(p);
+        
+        mark_dirty(current->domain, mfn);
 
         addr += count;
         buf  += count;
index 677c20c9d53429c7b5b04af56b9c36fb3c568e7b..3a7a875bcc8220109b493279347fa76b7de728dc 100644 (file)
@@ -33,6 +33,8 @@
 #include <asm/msr.h>
 #include <asm/apic.h>
 #include <asm/paging.h>
+#include <asm/shadow.h>
+#include <asm/p2m.h>
 #include <asm/hvm/hvm.h>
 #include <asm/hvm/support.h>
 #include <asm/hvm/vpt.h>
@@ -739,6 +741,7 @@ void hvm_io_assist(struct vcpu *v)
     ioreq_t *p;
     struct cpu_user_regs *regs;
     struct hvm_io_op *io_opp;
+    unsigned long gmfn;
 
     io_opp = &v->arch.hvm_vcpu.io_op;
     regs   = &io_opp->io_context;
@@ -763,6 +766,13 @@ void hvm_io_assist(struct vcpu *v)
     /* Copy register changes back into current guest state. */
     hvm_load_cpu_guest_regs(v, regs);
     memcpy(guest_cpu_user_regs(), regs, HVM_CONTEXT_STACK_BYTES);
+
+    /* Has memory been dirtied? */
+    if ( p->dir == IOREQ_READ && p->data_is_ptr ) 
+    {
+        gmfn = get_mfn_from_gpfn(paging_gva_to_gfn(v, p->data));
+        mark_dirty(v->domain, gmfn);
+    }
 }
 
 /*
index e3b4821010798dbb6c6db5700eb77fe461c5db3d..93233c83fc82b9e5eeb89605d2a6d3da8a92f07c 100644 (file)
@@ -981,7 +981,6 @@ mfn_t shadow_alloc(struct domain *d,
         INIT_LIST_HEAD(&sp[i].list);
         sp[i].type = shadow_type;
         sp[i].pinned = 0;
-        sp[i].logdirty = 0;
         sp[i].count = 0;
         sp[i].backpointer = backpointer;
         sp[i].next_shadow = NULL;
@@ -1230,7 +1229,6 @@ static unsigned int sh_set_allocation(struct domain *d,
             {
                 sp[j].type = 0;  
                 sp[j].pinned = 0;
-                sp[j].logdirty = 0;
                 sp[j].count = 0;
                 sp[j].mbz = 0;
                 sp[j].tlbflush_timestamp = 0; /* Not in any TLB */
@@ -2558,7 +2556,7 @@ static int shadow_one_bit_enable(struct domain *d, u32 mode)
     ASSERT(shadow_locked_by_me(d));
 
     /* Sanity check the call */
-    if ( d == current->domain || (d->arch.paging.mode & mode) )
+    if ( d == current->domain || (d->arch.paging.mode & mode) == mode )
     {
         return -EINVAL;
     }
@@ -2589,7 +2587,7 @@ static int shadow_one_bit_disable(struct domain *d, u32 mode)
     ASSERT(shadow_locked_by_me(d));
 
     /* Sanity check the call */
-    if ( d == current->domain || !(d->arch.paging.mode & mode) )
+    if ( d == current->domain || !((d->arch.paging.mode & mode) == mode) )
     {
         return -EINVAL;
     }
@@ -2646,17 +2644,7 @@ static int shadow_test_enable(struct domain *d)
 
     domain_pause(d);
     shadow_lock(d);
-
-    if ( shadow_mode_enabled(d) )
-    {
-        SHADOW_ERROR("Don't support enabling test mode"
-                      " on already shadowed doms\n");
-        ret = -EINVAL;
-        goto out;
-    }
-
     ret = shadow_one_bit_enable(d, PG_SH_enable);
- out:
     shadow_unlock(d);
     domain_unpause(d);
 
@@ -2722,10 +2710,10 @@ static int shadow_log_dirty_enable(struct domain *d)
 
     if ( shadow_mode_enabled(d) )
     {
-        SHADOW_ERROR("Don't (yet) support enabling log-dirty"
-                      " on already shadowed doms\n");
-        ret = -EINVAL;
-        goto out;
+        /* This domain already has some shadows: need to clear them out 
+         * of the way to make sure that all references to guest memory are 
+         * properly write-protected */
+        shadow_blow_tables(d);
     }
 
 #if (SHADOW_OPTIMIZATIONS & SHOPT_LINUX_L3_TOPLEVEL)
@@ -2917,12 +2905,18 @@ static int shadow_log_dirty_op(
 void sh_mark_dirty(struct domain *d, mfn_t gmfn)
 {
     unsigned long pfn;
-
-    ASSERT(shadow_locked_by_me(d));
+    int do_locking;
 
     if ( !shadow_mode_log_dirty(d) || !mfn_valid(gmfn) )
         return;
 
+    /* Although this is an externally visible function, we do not know
+     * whether the shadow lock will be held when it is called (since it
+     * can be called from __hvm_copy during emulation).
+     * If the lock isn't held, take it for the duration of the call. */
+    do_locking = !shadow_locked_by_me(d);
+    if ( do_locking ) shadow_lock(d);
+
     ASSERT(d->arch.paging.shadow.dirty_bitmap != NULL);
 
     /* We /really/ mean PFN here, even for non-translated guests. */
@@ -2962,13 +2956,8 @@ void sh_mark_dirty(struct domain *d, mfn_t gmfn)
                        mfn_to_page(gmfn)->count_info, 
                        mfn_to_page(gmfn)->u.inuse.type_info);
     }
-}
 
-void shadow_mark_dirty(struct domain *d, mfn_t gmfn)
-{
-    shadow_lock(d);
-    sh_mark_dirty(d, gmfn);
-    shadow_unlock(d);
+    if ( do_locking ) shadow_unlock(d);
 }
 
 /**************************************************************************/
@@ -2992,9 +2981,7 @@ int shadow_domctl(struct domain *d,
         if ( shadow_mode_log_dirty(d) )
             if ( (rc = shadow_log_dirty_disable(d)) != 0 ) 
                 return rc;
-        if ( is_hvm_domain(d) )
-            return -EINVAL;
-        if ( d->arch.paging.mode & PG_SH_enable )
+        if ( d->arch.paging.mode == PG_SH_enable )
             if ( (rc = shadow_test_disable(d)) != 0 ) 
                 return rc;
         return 0;
index 837e34733c40f7d94b30749041ae981377f34ad0..e96972a9d5ea59110862e91b5563646f7c6ab971 100644 (file)
@@ -101,14 +101,6 @@ get_fl1_shadow_status(struct vcpu *v, gfn_t gfn)
 /* Look for FL1 shadows in the hash table */
 {
     mfn_t smfn = shadow_hash_lookup(v, gfn_x(gfn), SH_type_fl1_shadow);
-
-    if ( unlikely(shadow_mode_log_dirty(v->domain) && mfn_valid(smfn)) )
-    {
-        struct shadow_page_info *sp = mfn_to_shadow_page(smfn);
-        if ( !(sp->logdirty) )
-            shadow_convert_to_log_dirty(v, smfn);
-    }
-
     return smfn;
 }
 
@@ -118,14 +110,6 @@ get_shadow_status(struct vcpu *v, mfn_t gmfn, u32 shadow_type)
 {
     mfn_t smfn = shadow_hash_lookup(v, mfn_x(gmfn), shadow_type);
     perfc_incrc(shadow_get_shadow_status);
-
-    if ( unlikely(shadow_mode_log_dirty(v->domain) && mfn_valid(smfn)) )
-    {
-        struct shadow_page_info *sp = mfn_to_shadow_page(smfn);
-        if ( !(sp->logdirty) )
-            shadow_convert_to_log_dirty(v, smfn);
-    }
-
     return smfn;
 }
 
@@ -136,12 +120,6 @@ set_fl1_shadow_status(struct vcpu *v, gfn_t gfn, mfn_t smfn)
     SHADOW_PRINTK("gfn=%"SH_PRI_gfn", type=%08x, smfn=%05lx\n",
                    gfn_x(gfn), SH_type_fl1_shadow, mfn_x(smfn));
 
-    if ( unlikely(shadow_mode_log_dirty(v->domain)) )
-        // mark this shadow as a log dirty shadow...
-        mfn_to_shadow_page(smfn)->logdirty = 1;
-    else
-        mfn_to_shadow_page(smfn)->logdirty = 0;
-
     shadow_hash_insert(v, gfn_x(gfn), SH_type_fl1_shadow, smfn);
 }
 
@@ -156,12 +134,6 @@ set_shadow_status(struct vcpu *v, mfn_t gmfn, u32 shadow_type, mfn_t smfn)
                    d->domain_id, v->vcpu_id, mfn_x(gmfn),
                    shadow_type, mfn_x(smfn));
 
-    if ( unlikely(shadow_mode_log_dirty(d)) )
-        // mark this shadow as a log dirty shadow...
-        mfn_to_shadow_page(smfn)->logdirty = 1;
-    else
-        mfn_to_shadow_page(smfn)->logdirty = 0;
-
 #ifdef CONFIG_COMPAT
     if ( !IS_COMPAT(d) || shadow_type != SH_type_l4_64_shadow )
 #endif
@@ -3994,6 +3966,8 @@ sh_x86_emulate_write(struct vcpu *v, unsigned long vaddr, void *src,
     /* If we are writing zeros to this page, might want to unshadow */
     if ( likely(bytes >= 4) && (*(u32 *)addr == 0) && is_lo_pte(vaddr) )
         check_for_early_unshadow(v, mfn);
+    
+    sh_mark_dirty(v->domain, mfn);
 
     sh_unmap_domain_page(addr);
     shadow_audit_tables(v);
@@ -4047,6 +4021,8 @@ sh_x86_emulate_cmpxchg(struct vcpu *v, unsigned long vaddr,
     if ( likely(bytes >= 4) && (*(u32 *)addr == 0) && is_lo_pte(vaddr) )
         check_for_early_unshadow(v, mfn);
 
+    sh_mark_dirty(v->domain, mfn);
+
     sh_unmap_domain_page(addr);
     shadow_audit_tables(v);
     return rv;
@@ -4087,6 +4063,8 @@ sh_x86_emulate_cmpxchg8b(struct vcpu *v, unsigned long vaddr,
     if ( *(u32 *)addr == 0 )
         check_for_early_unshadow(v, mfn);
 
+    sh_mark_dirty(v->domain, mfn);
+
     sh_unmap_domain_page(addr);
     shadow_audit_tables(v);
     return rv;
index 322871acb6766d1745c57253ff158fa8b8c3925c..479ed269599ee0f73fe7ba0e6af2cee76056b276 100644 (file)
@@ -229,8 +229,7 @@ struct shadow_page_info
     struct {
         unsigned int type:4;      /* What kind of shadow is this? */
         unsigned int pinned:1;    /* Is the shadow pinned? */
-        unsigned int logdirty:1;  /* Was it made in log-dirty mode? */
-        unsigned int count:26;    /* Reference count */
+        unsigned int count:27;    /* Reference count */
         u32 mbz;                  /* Must be zero: this is where the owner 
                                    * field lives in a non-shadow page */
     } __attribute__((packed));
index 5a3dbfc72e98e8a57cd94bb7c43f376ffe4fe161..cfd8e841c8196d1af1547ce8447e37d985323889 100644 (file)
@@ -87,12 +87,13 @@ void shadow_final_teardown(struct domain *d);
 
 /* Mark a page as dirty in the log-dirty bitmap: called when Xen 
  * makes changes to guest memory on its behalf. */
-void shadow_mark_dirty(struct domain *d, mfn_t gmfn);
+void sh_mark_dirty(struct domain *d, mfn_t gmfn);
 /* Cleaner version so we don't pepper shadow_mode tests all over the place */
 static inline void mark_dirty(struct domain *d, unsigned long gmfn)
 {
     if ( unlikely(shadow_mode_log_dirty(d)) )
-        shadow_mark_dirty(d, _mfn(gmfn));
+        /* See the comment about locking in sh_mark_dirty */
+        sh_mark_dirty(d, _mfn(gmfn));
 }
 
 /* Update all the things that are derived from the guest's CR0/CR3/CR4.